home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1993 July / InfoMagic USENET CD-ROM July 1993.ISO / sources / unix / volume13 / modemcap < prev    next >
Encoding:
Internet Message Format  |  1988-01-31  |  32.2 KB

  1. Subject:  v13i059:  Hardware-independant modem routines
  2. Newsgroups: comp.sources.unix
  3. Sender: sources
  4. Approved: rsalz@uunet.UU.NET
  5.  
  6. Submitted-by: The Beach Bum <ulysses!ihnp4!killer!jfh@seismo.CSS.GOV>
  7. Posting-number: Volume 13, Issue 59
  8. Archive-name: modemcap
  9.  
  10. This is a modem-independant dial(3) package, with a termcap-style
  11. description file.  No manual page -- refer to the relevant (SystemV)
  12. manuals.
  13.  
  14. #! /bin/sh
  15. # This is a shell archive, meaning:
  16. # 1. Remove everything above the #! /bin/sh line.
  17. # 2. Save the resulting text in a file.
  18. # 3. Execute the file with /bin/sh (not csh) to create:
  19. #    README
  20. #    makefile
  21. #    modemcap
  22. #    modemtype
  23. #    modemcap.h
  24. #    mgetent.c
  25. #    mgetstr.c
  26. #    mgetflag.c
  27. #    mgetnum.c
  28. #    mdial.c
  29. #    merror.c
  30. #    initmodem.c
  31. #    hangup.c
  32. #    dial.c
  33. #    call.c
  34. # This archive created: Mon Nov  2 13:32:08 1987
  35. export PATH; PATH=/bin:/usr/bin:$PATH
  36. if test -f 'README'
  37. then
  38.     echo shar: "will not over-write existing file 'README'"
  39. else
  40. cat << \SHAR_EOF > 'README'
  41. This package is a modem independent dial(3) package.  It provides a device
  42. independent method for dialing and manipulating modems.  The format of the
  43. description file is the ever present ;-) termcaps format.  You may want to
  44. read the modemcap file to see just what capabilities are present.
  45.  
  46. This is Release 1.1 of this software.  Please bear in mind that I haven't
  47. released this to the public before this release.
  48.  
  49. --< Start of the legal conditions of this software >--
  50.  
  51. This software is copyright 1987 John F. Haugh II, all rights reserved.
  52. Use, duplication and disclosure subject to the terms and conditions of
  53. the license agreement below.  This notice is intended to have legal
  54. significance, and not to be taken lightly.  If you have any questions,
  55. please contact the author at the address below.  This copyright covers
  56. the entire software distribution it is enclosed with.  Removing this
  57. copyright is a violation of federal copyright law.  Please consult an
  58. attorney if you have any questions regarding the legal ramifications of
  59. this agreement.
  60.  
  61. This software is licensed subject to the following terms and conditions.
  62. In order that this product may expand into the universe to fill the current
  63. (void) in this area, it is my intention that this software be widely
  64. distributed, and maintained in a consistent fashion.  To this end, you
  65. are authorized to redistribute this software in either source or binary
  66. format, provided that, this agreement is retained as part of the release,
  67. no direct profit is realized from the sale or transfer of this software,
  68. and that credit is given the author for this work.  To facilitate this
  69. package coming into acceptance, you must provide library versions of this
  70. software and any documentation included with this package when distributing
  71. binary versions embedded in your products.  Paying royalties would be
  72. nice and you won't do it anyway, so don't even pretend to be nice people
  73. unless you really want me to stay on top of this thing.  Author retains
  74. all rights to derived works, and as a condition to your making modifications
  75. to the source code, you are required by this agreement to provide detailed
  76. notes concerning the actual modifications and the motivation behind the
  77. modification itself.  Making the documentation look better is a nice idea
  78. also.  And since I'm very lazy, please send me your documentation.  You
  79. don't have to, but standardized documentation is a Good Thing.
  80.  
  81. The author provides this software without warrantee.  The user accepts by
  82. use all responsibility for the performance (or lack thereof ;-) of this
  83. software, including loss of profits, reputation, or job.
  84.  
  85. --< End of the legal stuff, now for the documentation. >--
  86.  
  87. call.c - a test program.  do a `make all' to create the library and compile
  88. the call program.  read all the documentation before trying it out.
  89.  
  90. dial(3L) - a version of the standard dial(3) command which should be fairly
  91. compatible with the one in your manual ...  has both dial() and undial()
  92. routines.  see your manpage for more details.
  93.  
  94. hangup.c/hangup(3L) - a routine that attempts to absolutely hangup a modem.
  95. it uses the modem capabilities database to figure out the best way to
  96. hangup a modem.  it supports both hangup on DTR and hangup on command.
  97.  
  98. initmodem.c/initmodem(3L) - this routine takes a character pointer to a
  99. modem name as it appears in the database and a file descriptor from a
  100. open() call, and loads the database information.  after the database is
  101. loaded, the modem is placed in the command mode.  beware, initmodem()
  102. may make an alarm(2) call if the InitializationDelay requirement is present.
  103.  
  104. mdial.c/mdial(3L) - this routine builds a dial command string to give
  105. to the dialer.  this is the weakest routine in the package, because i don't
  106. have that many different modems around here, and hayes is pretty damned
  107. common, so i don't see many others.  the first argument is a character string
  108. telephone number, digits only, or if you understand your modem (boo on me)
  109. you can put in pause commands.  the second argument is a file descriptor
  110. from an open() call. this routine _will_ be the first to get fixed.
  111.  
  112. merror.c/merror(3L) - this routine is a modemcap replacement for perror.
  113. an `int merrno' variable is maintained by the routines.  after an error
  114. return, you can call merror with a character pointer just like perror(3)
  115. and have a message printed on your standard error output.
  116.  
  117. mgetent.c/mgetent(3L) - this is a low level routine you shouldn't be
  118. calling anyway.  it works like tgetent(3), only different.  mostly, it
  119. doesn't have the neat things.  the first argument is a pointer to a
  120. character buffer where the entry will be placed.  the second argument
  121. is a pointer to the modem name.
  122.  
  123. mgetflag.c/mgetflag(3L) - just like tgetflag.  this is a low level
  124. routine you might just want to use.  in particular, `if (mgetflag ("hc"))'
  125. tests for modem hanging up on DTR being negated.  `if (HC)' does the
  126. same thing after mgetent() ...
  127.  
  128. mgetnum.c/mgetnum(3L) - just like tgetnum.  don't see much use for using
  129. it.
  130.  
  131. mgetstr.c/mgetstr(3L) - just like tgetstr, except it has a few quirks.
  132. octal escapes are all three digits.  the format '^c' where 'c' is some
  133. character, only works with upper case letters.  correctly at least.
  134. ain't no way to get a null into the string, no how.
  135.  
  136. /etc/modemcap - a modem capabilities database.  read the file for more
  137. details.
  138.  
  139. /etc/modemtype - a modem/port mapping table.  look at the example file.
  140.  
  141. you will need to make entries for your devices in the L-devices file.
  142. the speed listed must be a legal speed according to the modemcap file.
  143. any compilation errors or warnings should be brought to my attention. i
  144. didn't get any the last time i compiled all this stuff.
  145.  
  146. the source is well enough (i'm lieing) documented for anyone to fix.
  147. please don't add your local improvement.  if you insist, make the mods
  148. and send me context diffs.  i'll tell you what i think about the change.
  149. remember, according to the license you must let me in on what you are
  150. doing.  this is in everyones best interest.
  151.  
  152. --< End of the documentation, now for my personal philosophical b.s. >--
  153.  
  154. It is not my intention to limit the use of this software or your profits,
  155. except where such use is inconsistent with the spirit of humanity, whatever
  156. the hell that means.  I don't care how much money you make selling your
  157. new terminal program, just don't go jacking the price up because you
  158. have added this thing.  I will only work on this package if I get feedback
  159. and I have some motivation, other than being a nice guy.  I think I've been
  160. nice enough by putting this thing out there.  If what you want makes sense
  161. in a real way, I will probably include your suggestions, and if you are
  162. polite, I might just give you credit ;-)  So don't be a jerk and pretend
  163. that anyone actually works for free.  I have a car note just like you.
  164.  
  165. By way of this license and the legal mumbo-jumbo, I hope to keep people
  166. from ripping me off, and totally trashing and perverting the integrity
  167. of the code.  Please, don't construe this agreement to be limiting in
  168. a negative way.  I hope to provide just enough limits to keep the code
  169. consistent and portable across all machine environments, and hopefully,
  170. you will use this thing enough that it becomes better and more useful
  171. and fills the need for such a thing.  Who knows, we both might just make
  172. some money off of this thing.
  173.  
  174. --
  175. John F. Haugh II        QUOTE: "The important thing is to not stop
  176. 7825 McCallum Blvd.            questioning" -- Albert Einstein
  177. Apt. 510            TELCO: (214) 250-3311
  178. Dallas, TX 75252        UUCP:  { backbone } !ihnp4!killer!jfh
  179. SHAR_EOF
  180. fi
  181. if test -f 'makefile'
  182. then
  183.     echo shar: "will not over-write existing file 'makefile'"
  184. else
  185. cat << \SHAR_EOF > 'makefile'
  186. # Your library directory.
  187. LIBDIR=/usr/lib
  188. # Your local command directory.
  189. LBIN=/usr/local/bin
  190. OSFLAG=-DUNIX_S5    # For System V machines.
  191. # OSFLAG=-DUNIX_V7    # For Version 7 machines.
  192. # For those poor people who need ranlib
  193. # RANLIB=ranlib $(LIBDIR)/libmodemcap.a
  194. # Standard Bourne shell.
  195. SHELL=/bin/sh
  196.  
  197. CFLAGS=-O
  198. LDFLAGS=-s
  199.  
  200. OFILES=mgetent.o mgetstr.o mgetflag.o mgetnum.o mdial.o merror.o \
  201.     initmodem.o hangup.o dial.o
  202.  
  203. CFILES=mgetent.c mgetstr.c mgetflag.c mgetnum.c mdial.c merror.c \
  204.     initmodem.c hangup.c dial.c
  205.  
  206. LFILES=libmodemcap.a(mgetent.o)\
  207.     libmodemcap.a(mgetstr.o)\
  208.     libmodemcap.a(mgetflag.o)\
  209.     libmodemcap.a(mgetnum.o)\
  210.     libmodemcap.a(mdial.o)\
  211.     libmodemcap.a(merror.o)\
  212.     libmodemcap.a(initmodem.o)\
  213.     libmodemcap.a(hangup.o)\
  214.     libmodemcap.a(dial.o)
  215.  
  216. all:    $(LFILES)
  217.  
  218. install:    all call
  219.     cp modemcap.h /usr/include
  220.     cp modemcap /etc/modemcap
  221.     cp modemtype /etc/modemtype
  222.     cp libmodemcap.a $(LIBDIR)
  223.     chmod 644 /usr/include/modemcap.h /etc/modemcap /etc/modemtype $(LIBDIR)/libmodemcap.a
  224.     cp call $(LBIN)/call
  225.     chmod 711 $(LBIN)/call
  226.  
  227. call:    call.c libmodemcap.a
  228.     cc $(LDFLAGS) $(CFLAGS) call.c libmodemcap.a -o call
  229.  
  230. initmodem.o:    initmodem.c /usr/include/modemcap.h
  231.  
  232. mdial.o:    mdial.c /usr/include/modemcap.h
  233.  
  234. hangup.o:    hangup.c /usr/include/modemcap.h
  235.  
  236. dial.o:    dial.c    /usr/include/modemcap.h
  237.  
  238. shar:    README $(CFILES) makefile modemcap modemtype modemcap.h call.c
  239.     shar README makefile modemcap modemtype modemcap.h $(CFILES) call.c > modem.shar
  240. SHAR_EOF
  241. fi
  242. if test -f 'modemcap'
  243. then
  244.     echo shar: "will not over-write existing file 'modemcap'"
  245. else
  246. cat << \SHAR_EOF > 'modemcap'
  247. #
  248. #       @(#)modemcap    1.0
  249. #
  250. #       First attempt at a modem capabilities database.
  251. #
  252. #       Capabilities are:
  253. #
  254. #       Name    Type    Meaning
  255. #
  256. #       as      flag    Numbers are in ASCII, not binary
  257. #       at      string  Attention string, forces model into command mode from online mode
  258. #       ad      number  Delay after AS
  259. #       bd      number  Highest online baud rate
  260. #       bl      number  Alternate lower baud rate
  261. #       cs      string  Command start string
  262. #       ce      string  Command end string (required if CS is present)
  263. #       co      string  String from modem on remote connection at BD baud rate
  264. #       cl      string  String from modem on remote connection at BL baud rate
  265. #       di      flag    Modem has a dialer
  266. #       ds      string  Start dial command string
  267. #       de      string  End dial command string (required if DS is present)
  268. #       is      string  Initialization string, resets modem to offline, ready to dial
  269. #       id      number  Delay after IS
  270. #       hc      flag    Modem hangs up when DTR drops
  271. #       hu      string  Hangup command
  272. #       tt      flag    Modem dials touchtone by default (or DS is set that way)
  273. #
  274. #       All commands, such as DS (dial command) and HU (hang up) will be prefixed by
  275. #       CS and ended with CE.  If there is a common prefix and suffix, use this feature.
  276. #       Otherwise, each command will have to have the entire string built in.
  277. #
  278. hy|hayes|Hayes Smartmodem 1200:\
  279.     :as:at=+++:ad#6:bd#1200:bl#300:cs=AT:ce=\r:co=CONNECT:\
  280.     :cl=CONNECT:di:ds=DT :de=:is=ATQ0 V1 E1\r:id#2:\
  281.     :hc:hu=H0 V0 E0 Q1:tt:
  282. si|mk12|Signalman Mark XII:\
  283.         :as:at=+++:ad#6:bd#1200:bl#300:cs=AT:ce=\r:co=CONNECT 1200:\
  284.         :cl=CONNECT:di:ds=DT :de=:is=ATQ0 V1 E1\r:id#2:\
  285.         :hu=H0 V0 E0 Q1:tt:
  286. ds|dc300|Radio Shack Direct-Connect 300 Modem:\
  287.         :bd#300:bl#110:
  288. SHAR_EOF
  289. fi
  290. if test -f 'modemtype'
  291. then
  292.     echo shar: "will not over-write existing file 'modemtype'"
  293. else
  294. cat << \SHAR_EOF > 'modemtype'
  295. hayes1200 tty38
  296. hayes1200 tty39
  297. ch1770 modem
  298. SHAR_EOF
  299. fi
  300. if test -f 'modemcap.h'
  301. then
  302.     echo shar: "will not over-write existing file 'modemcap.h'"
  303. else
  304. cat << \SHAR_EOF > 'modemcap.h'
  305. /* 
  306.  *      @(#)modemcap.h  1.0
  307.  *
  308.  *      names of variables and whatnots for modemcap file
  309.  */
  310.  
  311. char    AS,             /* True if numbers dialed in ASCII, False for binary digits     */
  312.         DI,             /* True if modem can dial numbers, False otherwise              */
  313.         HC,             /* True if modem hangs up when DTR drops, False otherwise       */
  314.         TT;             /* True if modem uses touchtone by default, False for pulse     */
  315.  
  316. char    *AT,            /* Enter command state when online                              */
  317.         *CS,            /* Command start string                                         */
  318.         *CE,            /* Command end string - must be present if CS is                */
  319.         *DS,            /* Dial command string                                          */
  320.         *DE,            /* End of dial command string - must be present if DS is        */
  321.         *CO,            /* Connection made at primary baud rate                         */
  322.         *CL,            /* Connection made at secondary (lower) baud rate               */
  323.         *IS,            /* Initialization string - reset modem to onhook and ready      */
  324.         *HU;            /* Hangup command                                               */
  325.  
  326. int     AD,             /* Delay after AT string before next command                    */
  327.         BD,             /* Highest communications baud rate                             */
  328.         BL,             /* Another, lower baud rate                                     */
  329.         ID;             /* Delay time after initialization                              */
  330.  
  331. /*
  332.  * The dial command is the principle string that must be built.
  333.  * The routines will build a dial command as follows:
  334.  *
  335.  *      <CS><DS><phone-number><DE><CE>
  336.  *
  337.  * Note that the DE and CE strings are present ALWAYS.
  338.  * This procedure will be used to dial phone numbers if the DI flag is true.
  339.  * If this isn't the way to dial numbers,
  340.  * DO NOT SET DI IN THE MODEMCAP FILE!!!
  341.  */
  342.  
  343. /*
  344.  * The type of modem is determined by reading the file "_MODEMTYPE_".  This
  345.  * is similiar to the way curses works by reading the ttytype file.
  346.  */
  347.  
  348. #define    _MODEMTYPE_    "/etc/modemtype"
  349.  
  350. /*
  351.  * a hangup command will be performed as follows:
  352.  *
  353.  *      1). any attention string (AT) will be sent followed by the delay (AD)
  354.  *      2). modem should now be in command state, send hangup (HU) command
  355.  *      3). send initialization string (IS) followed by the delay (ID)
  356.  *
  357.  * It is important that you determine a correct AT and HU string
  358.  *  to perform this function.
  359.  * If the modem hangs up when DTR falls (even if there is a HU string),
  360.  *  declare the flag HC (for Hangup on Close).
  361.  */
  362.  
  363. SHAR_EOF
  364. fi
  365. if test -f 'mgetent.c'
  366. then
  367.     echo shar: "will not over-write existing file 'mgetent.c'"
  368. else
  369. cat << \SHAR_EOF > 'mgetent.c'
  370. #include <stdio.h>
  371.  
  372. char    *__modemcap;
  373. char    *MODEMCAP = "/etc/modemcap";
  374.  
  375. static    isent (ent, name)
  376. char    *ent;
  377. char    *name;
  378. {
  379.     char    buf[16];
  380.     register int    i;
  381.  
  382.     while (*ent != ':' && *ent != 0) {
  383.         for (i = 0;*ent != ':' && *ent != '|' && *ent != 0 && i < 15;i++)
  384.             buf[i] = *ent++;
  385.  
  386.         if (*ent == '|')
  387.             ent++;
  388.  
  389.         buf[i] = 0;
  390.         if (strcmp (buf, name) == 0)
  391.             return (1);
  392.     }
  393.     return (0);
  394. }
  395.  
  396. mgetent (bp, name)
  397. char    *bp;
  398. char    *name;
  399. {
  400.     char    buf[1024];
  401.     register char    *cp;
  402.     register FILE    *modemcap;
  403.     register int    i;
  404.     char    *getenv ();
  405.  
  406.     if ((cp = getenv ("MODEMCAP")) != NULL) {
  407.         if (*cp != '/') {
  408.             if (isent (cp, name)) {
  409.                 strcpy (buf, cp);
  410.                 return (1);
  411.             }
  412.         }
  413.         MODEMCAP = cp;
  414.     }
  415.     if ((modemcap = fopen (MODEMCAP, "r")) == NULL)
  416.         return (-1);
  417.  
  418.     while (fgets (buf, 512, modemcap) != NULL) {
  419.         if (buf[0] == '#')                /* skip all comment lines        */
  420.             continue;
  421.  
  422.         i = strlen (buf) - 1;                /* find last character in line        */
  423.         buf[i] = 0;                    /* remove trailing newline        */
  424.         if (i == 0)                    /* ignore blank lines            */
  425.             continue;
  426.  
  427.         while (buf[(i = strlen (buf) - 1)] == '\\') {    /* is last character a \\, still more    */
  428.             cp = &buf[i];                /* find last character            */
  429.             cp[0] = 0;                /* nullify, end of this part        */
  430.             if (fgets (cp, 512, modemcap) == NULL)    /* end of file?    ...            */
  431.                 break;                /* ... end of entry            */
  432.  
  433.             cp[strlen (cp) - 1] = 0;        /* remove trailing newline        */
  434.             if (cp[0] == '#') {            /* comment line? ...            */
  435.                 cp[0] = 0;            /* remove that line            */
  436.                 continue;            /* go get another line            */
  437.             }
  438.         }
  439.         if (isent (buf, name)) {
  440.             __modemcap = bp;
  441.             strcpy (bp, buf);
  442.             fclose (modemcap);
  443.             return (1);
  444.         }
  445.     }
  446.     fclose (modemcap);
  447.     return (0);
  448. }
  449. SHAR_EOF
  450. fi
  451. if test -f 'mgetstr.c'
  452. then
  453.     echo shar: "will not over-write existing file 'mgetstr.c'"
  454. else
  455. cat << \SHAR_EOF > 'mgetstr.c'
  456. extern    char    *__modemcap;
  457.  
  458. char    *mgetstr (id, area)
  459. register char    *id;
  460. register char    **area;
  461. {
  462.     register char    *cp = __modemcap;
  463.     register char    *str = *area;        /* start of current string        */
  464.  
  465.     if (__modemcap == (char *) 0)        /* has mgetent() been called? ...    */
  466.         return ((char *) 0);            /* ... no, can't find string    */
  467.  
  468.     while (*cp != ':' && *cp != 0)        /* find first entry in cap        */
  469.         cp++;
  470.  
  471.     if (*cp == 0)                /* empty entry???            */
  472.         return ((char *) 0);            /* ... yes, bad modemcap entry        */
  473.     else
  474.         cp++;                /* point to first character in next    */
  475.  
  476.     while (*cp != 0) {            /* until entry found or end of entry    */
  477.         if (cp[0] == id[0] && cp[1] == id[1]) {    /* found entry!!!        */
  478.             if (cp[2] != '=')    /* is it a string value???        */
  479.                 return ((char *) 0);    /* no, something else            */
  480.             else
  481.                 break;        /* yes, entry was found            */
  482.         } else {            /* not entry, skip this entire entry    */
  483.             while (*cp != ':' && *cp != 0)
  484.                 cp++;        /* search for end of current entry    */
  485.  
  486.             if (*cp != 0)
  487.                 cp++;        /* skip terminating character        */
  488.         }
  489.     }
  490.     if (*cp == 0)                /* end of modem cap entry        */
  491.         return ((char *) 0);
  492.  
  493.     cp += 3;                /* point to actual string        */
  494.     while (*cp != ':' && *cp != 0) {    /* for every character in string ...    */
  495.         if (*cp == '\\') {        /* translate escaped character        */
  496.             cp++;
  497.             switch (*cp) {
  498.                 case 'n':    /* newline            */
  499.                     **area = '\n';
  500.                     (*area)++;
  501.                     cp++;
  502.                     break;
  503.                 case 'r':    /* carriage return        */
  504.                     **area = '\r';
  505.                     (*area)++;
  506.                     cp++;
  507.                     break;
  508.                 case 'b':    /* backspace            */
  509.                     **area = '\b';
  510.                     (*area)++;
  511.                     cp++;
  512.                     break;
  513.                 case 'f':    /* form feed            */
  514.                     **area = '\f';
  515.                     (*area)++;
  516.                     cp++;
  517.                     break;
  518.                 case 't':    /* tab                */
  519.                     **area = '\t';
  520.                     (*area)++;
  521.                     cp++;
  522.                     break;
  523.                 case 'E':    /* Escape character        */
  524.                     **area = 033;
  525.                     (*area)++;
  526.                     cp++;
  527.                     break;
  528.                 case '0':
  529.                 case '1':
  530.                 case '2':
  531.                 case '3':
  532.                 case '4':
  533.                 case '5':
  534.                 case '6':
  535.                 case '7':
  536.                     **area = ((cp[0] - '0') << 6) +
  537.                          ((cp[1] - '0') << 3) +
  538.                           (cp[2] - '0');
  539.                     (*area)++;
  540.                     cp += 3;
  541.                     break;
  542.                 default:
  543.                     **area = *cp++;
  544.                     (*area)++;
  545.                     break;
  546.             }
  547.         } else if (*cp == '^') {    /* some control character        */
  548.             cp++;
  549.             if (*cp >= '@' && *cp <= '_') {
  550.                 **area = *cp - '@';
  551.                 (*area)++;
  552.             }
  553.             cp++;
  554.         } else {            /* some normal character        */
  555.             **area = *cp++;        /* put character in area        */
  556.             (*area)++;
  557.         }
  558.     }
  559.     *((*area)++) = 0;            /* null terminate area and string    */
  560.     return (str);                /* return pointer to start of string    */
  561. }
  562. SHAR_EOF
  563. fi
  564. if test -f 'mgetflag.c'
  565. then
  566.     echo shar: "will not over-write existing file 'mgetflag.c'"
  567. else
  568. cat << \SHAR_EOF > 'mgetflag.c'
  569. extern    char    *__modemcap;
  570.  
  571. mgetflag (id)
  572. register char    *id;
  573. {
  574.     register char    *cp = __modemcap;
  575.  
  576.     if (__modemcap == (char *) 0)        /* has mgetent() been called? ...    */
  577.         return (-1);            /* ... no, can't find number        */
  578.  
  579.     while (*cp != ':' && *cp != 0)        /* find first entry in cap        */
  580.         cp++;
  581.  
  582.     if (*cp == 0)                /* empty entry???            */
  583.         return (0);            /* ... yes, bad modemcap entry        */
  584.     else
  585.         cp++;                /* point to first character in next    */
  586.  
  587.     while (*cp != 0) {            /* until entry found or end of entry    */
  588.         if (cp[0] == id[0] && cp[1] == id[1])    /* found entry!!!        */
  589.             return (1);        /* return true                */
  590.         else {            /* not entry, skip this entire entry    */
  591.             while (*cp != ':' && *cp != 0)
  592.                 cp++;        /* search for end of current entry    */
  593.  
  594.             if (*cp != 0)
  595.                 cp++;        /* skip terminating character        */
  596.         }
  597.     }
  598.     return (0);
  599. }
  600. SHAR_EOF
  601. fi
  602. if test -f 'mgetnum.c'
  603. then
  604.     echo shar: "will not over-write existing file 'mgetnum.c'"
  605. else
  606. cat << \SHAR_EOF > 'mgetnum.c'
  607. extern    char    *__modemcap;
  608.  
  609. mgetnum (id)
  610. register char    *id;
  611. {
  612.     register char    *cp = __modemcap;
  613.  
  614.     if (__modemcap == (char *) 0)        /* has mgetent() been called? ...    */
  615.         return (-1);            /* ... no, can't find number        */
  616.  
  617.     while (*cp != ':' && *cp != 0)        /* find first entry in cap        */
  618.         cp++;
  619.  
  620.     if (*cp == 0)                /* empty entry???            */
  621.         return (-1);            /* ... yes, bad modemcap entry        */
  622.     else
  623.         cp++;                /* point to first character in next    */
  624.  
  625.     while (*cp != 0) {            /* until entry found or end of entry    */
  626.         if (cp[0] == id[0] && cp[1] == id[1]) {    /* found entry!!!        */
  627.             if (cp[2] != '#')    /* is it a numeric value???        */
  628.                 return (-1);    /* no, something else            */
  629.  
  630.             return (atoi (&cp[3]));    /* return value (just after #)        */
  631.         } else {            /* not entry, skip this entire entry    */
  632.             while (*cp != ':' && *cp != 0)
  633.                 cp++;        /* search for end of current entry    */
  634.  
  635.             if (*cp != 0)
  636.                 cp++;        /* skip terminating character        */
  637.         }
  638.     }
  639.     return (-1);
  640. }
  641. SHAR_EOF
  642. fi
  643. if test -f 'mdial.c'
  644. then
  645.     echo shar: "will not over-write existing file 'mdial.c'"
  646. else
  647. cat << \SHAR_EOF > 'mdial.c'
  648. #include "modemcap.h"
  649. #include <setjmp.h>
  650. #include <signal.h>
  651. #include <dial.h>
  652.  
  653. static    jmp_buf    env;        /* long jump buffer if timeout in read    */
  654. extern    int    merrno;
  655.  
  656. static    timeout ()
  657. {
  658.     longjmp  (env, 1);
  659. }
  660.  
  661. mdial (telno, fd)
  662. char    *telno;
  663. int    fd;
  664. {
  665.     char    buf[64];    /* telephone buffer if AS is false */
  666.     char    command[80];    /* dial command buffer */
  667.     int    i, j;        /* index and length of telephone number */
  668.     char    c;        /* single character for connection verification */
  669.  
  670.     if (! DI)
  671.         return (merrno = A_PROB); /* can't dial phone anyhow */
  672.  
  673.     if (! AS)        /* never used any other kind of modem */
  674.         return (merrno = A_PROB);
  675.     else            /* normal ascii character phone numbers    */
  676.         strcpy (buf, telno);
  677.  
  678.     sprintf (command, "%s%s%s%s%s", CS, DS, buf, DE, CE);
  679.     if (setjmp (env) != 0) {    
  680.         signal (SIGALRM, SIG_DFL);
  681.         return (merrno = D_HUNG);
  682.     }
  683.     signal (SIGALRM, timeout);
  684.     alarm (10);
  685.     write (fd, command, strlen (command));
  686.  
  687.     if (CO) {    /* verify connection */
  688.         if (setjmp (env) != 0) {    
  689.             signal (SIGALRM, SIG_DFL);
  690.             return (merrno = A_PROB);
  691.         }
  692.         signal (SIGALRM, timeout);
  693.         if (TT)
  694.             alarm (30);
  695.         else
  696.             alarm (30 + strlen (telno) / 2);
  697.  
  698.         for (i = 0;CO[i] != 0;) {
  699.             if (read (fd, &c, 1) != 1)
  700.                 continue;
  701.             
  702.             if (CO[i] == c)
  703.                 i++;
  704.             else
  705.                 i = 0;
  706.         }
  707.         return (0);
  708.     }
  709.     return (0);
  710. }
  711. SHAR_EOF
  712. fi
  713. if test -f 'merror.c'
  714. then
  715.     echo shar: "will not over-write existing file 'merror.c'"
  716. else
  717. cat << \SHAR_EOF > 'merror.c'
  718. #include <stdio.h>
  719.  
  720. int    merrno;
  721.  
  722. char    *_merr_list[] = {
  723.     "No error",
  724.     "Interrupt occurred",
  725.     "Dialer Hung",
  726.     "No answer",
  727.     "Illegal baud rate",
  728.     "ACU Problem",
  729.     "Line Problem",
  730.     "Can't open LDEVS file",
  731.     "Requested device not available",
  732.     "Requested device not known",
  733.     "No device available at requested baud",
  734.     "No device known at requested baud"
  735. };
  736.  
  737. int    _msys_nerr = (sizeof (_merr_list) / sizeof (char *));
  738.  
  739. merror (s)
  740. char    *s;
  741. {
  742.     int    i = - merrno;
  743.  
  744.     if (0 <= i && i < _msys_nerr)
  745.         fprintf (stderr, "%s: %s\n", s, _merr_list[i]);
  746.     else
  747.         fprintf (stderr, "%s: Error %d\n", s, merrno);
  748. }
  749. SHAR_EOF
  750. fi
  751. if test -f 'initmodem.c'
  752. then
  753.     echo shar: "will not over-write existing file 'initmodem.c'"
  754. else
  755. cat << \SHAR_EOF > 'initmodem.c'
  756. #include "modemcap.h"
  757.  
  758. static    char    f_names[] = "asditthc";
  759. static    char    *f_caps[] = {
  760.     &AS, &DI, &TT, &HC
  761. };
  762.  
  763. static    char    i_names[] = "bdblidad";
  764. static    int    *i_caps[] = {
  765.     &BD, &BL, &ID, &AD
  766. };
  767.  
  768. static    char    c_names[] = "cscedsdeiscoclathu";
  769. static    char    **c_caps[] = {
  770.     &CS, &CE, &DS, &DE, &IS, &CO, &CL, &AT, &HU
  771. };
  772.  
  773. initmodem (modem, fd)
  774. char    *modem;                    /* name of modem        */
  775. int    fd;                    /* channel to modem        */
  776. {
  777.     static    char    mcapbuf[1024];
  778.     static    char    area[1024];
  779.     char    *ap = area;
  780.     register char    *cp;
  781.     register int    i, j;
  782.     register char    *s;
  783.     char    *mgetstr ();
  784.  
  785.     if (mgetent (mcapbuf, modem) != 1)
  786.         return (0);
  787.  
  788.     for (i = 0, cp = f_names;*cp;i++, cp += 2)
  789.         *(f_caps[i]) = mgetflag (cp);
  790.  
  791.     for (i = 0, cp = i_names;*cp;i++, cp += 2) {
  792.         j = mgetnum (cp);
  793.         if (j >= 0)
  794.             *(i_caps[i]) = j;
  795.         else
  796.             *(i_caps[i]) = 0;
  797.     }
  798.     for (i = 0, cp = c_names;*cp;i++, cp += 2)
  799.         *(c_caps[i]) = mgetstr (cp, &ap);
  800.  
  801.     if (IS != (char *) 0) {
  802.         write (fd, IS, strlen (IS));
  803.         if (ID)
  804.             sleep (ID);
  805.     }
  806.     return (1);
  807. }
  808. SHAR_EOF
  809. fi
  810. if test -f 'hangup.c'
  811. then
  812.     echo shar: "will not over-write existing file 'hangup.c'"
  813. else
  814. cat << \SHAR_EOF > 'hangup.c'
  815. #include "modemcap.h"
  816. #ifdef    UNIX_S5
  817. #include <termio.h>
  818. #endif
  819. #ifdef    UNIX_V7
  820. #include <sgtty.h>
  821. #endif
  822.  
  823. extern    int    merrno;
  824.  
  825. hangup (fd)
  826. int    fd;
  827. {
  828. #ifdef    UNIX_S5
  829.     struct    termio    termio;
  830.     struct    termio    hupcl;
  831. #endif
  832. #ifdef    UNIX_V7
  833.     struct    sgttyb    termio;
  834.     struct    sgttyb    hupcl;
  835. #endif
  836.     if (HU == (char *) 0 && HC == 0) {
  837.         undial (fd);
  838.         return (0);
  839.     }
  840.     if (AT != (char *) 0) {
  841.         write (fd, AT, strlen (AT));
  842.         if (AD)
  843.             sleep (AD);
  844.     }
  845.     if (HU) {
  846.         if (CS)
  847.             write (fd, CS, strlen (CS));
  848.         write (fd, HU, strlen (HU));
  849.         if (CE)
  850.             write (fd, CE, strlen (CE));
  851.  
  852.         if (IS) {
  853.             write (fd, IS, strlen (IS));
  854.             if (ID)
  855.                 sleep (ID);
  856.         }
  857.         undial (fd);
  858.         return (1);
  859.     }
  860. #ifdef    UNIX_S5
  861.     ioctl (fd, TCGETA, &termio);
  862.     ioctl (fd, TCGETA, &hupcl);
  863.     
  864.     hupcl.c_cflag &= ~CBAUD;
  865.     hupcl.c_cflag |= HUPCL;
  866.  
  867.     ioctl (fd, TCSETA, &hupcl);
  868.     sleep (2);
  869.     ioctl (fd, TCSETA, &termio);
  870. #endif
  871. #ifdef    UNIX_V7
  872.     gtty (fd, &termio);
  873.     gtty (fd, &hupcl);
  874.  
  875.     hupcl.sg_ispeed = B0;
  876.     hupcl.sg_ospeed = B0;
  877.     stty (fd, &hupcl);
  878.     sleep (2);
  879.     stty (fd, &termio);
  880. #endif
  881.     undial (fd);
  882.     return (1);
  883. }
  884. SHAR_EOF
  885. fi
  886. if test -f 'dial.c'
  887. then
  888.     echo shar: "will not over-write existing file 'dial.c'"
  889. else
  890. cat << \SHAR_EOF > 'dial.c'
  891. #include <fcntl.h>
  892. #include <dial.h>
  893. #include <signal.h>
  894. #include <stdio.h>
  895. #include "modemcap.h"
  896.  
  897. #ifdef    UNIX_V7
  898. typedef    int    void;
  899. #endif
  900. static    char    lockfile[64];
  901. static    int    modemfd = -1;
  902. extern    int    merrno;
  903.  
  904. static    findline (line, baud)
  905. char    *line;
  906. int    baud;
  907. {
  908.     int    exists = 0;
  909.     int    l_baud;
  910.     char    l_line[DVC_LEN+1];
  911.     char    l_type[DVC_LEN+1];
  912.     char    buf[64];
  913.     FILE    *fp;
  914.  
  915.     if ((fp = fopen (LDEVS, "r")) == NULL)
  916.         return (merrno = NO_Ldv);
  917.  
  918.     while (fgets (buf, 64, fp) != NULL) {
  919.         if (buf[0] == '#')        /* ignore comment lines            */
  920.             continue;
  921.  
  922.         if (sscanf (buf, "%s%s%*s%d", l_type, l_line, &l_baud) != 3)
  923.             continue;        /* mangled line                */
  924.  
  925.         if (strcmp (l_type, "DIR") != 0)
  926.             continue;        /* not a direct connect line        */
  927.  
  928.         if (strcmp (l_line, line) == 0)
  929.             exists++;        /* say device exists at some baud rate    */
  930.         else
  931.             continue;        /* wrong device                */
  932.  
  933.         if (l_baud == baud) {        /* found device at desired baud rate    */
  934.             fclose (fp);
  935.             return (1);
  936.         }
  937.     }
  938.     if (exists)
  939.         return (merrno = ILL_BD);
  940.     else
  941.         return (merrno = DV_NT_K);
  942. }
  943.  
  944. static    char    *findmodem (line)
  945. {
  946.     static    char    modemtype[16];
  947.     char    device[DVC_LEN + 1];
  948.     char    buf[82];
  949.     FILE    *fp;
  950.  
  951.     if ((fp = fopen (_MODEMTYPE_, "r")) == NULL)
  952.         return (NULL);
  953.  
  954.     while (fgets (buf, 82, fp) != NULL) {
  955.         if (buf[0] == '#')
  956.             continue;
  957.  
  958.         sscanf (buf, "%s%s\n", modemtype, device);
  959.         if (strcmp (line, device) == 0) {
  960.             fclose (fp);
  961.             return (modemtype);
  962.         }
  963.     }
  964.     fclose (fp);
  965.     return (NULL);
  966. }
  967.  
  968. struct speedlist {
  969.     int    value;
  970.     int    name;
  971. } speeds[] = {
  972.     {    0,     0},
  973.     {  110,  B110},
  974.     {  300,  B300},
  975.     {  600,  B600},
  976.     { 1200, B1200},
  977.     { 2400, B2400},
  978.     { 4800, B4800},
  979.     { 9600, B9600},
  980.     {19200, EXTA},
  981.     {38400, EXTB},
  982.     {   -1, -1}
  983. };
  984.  
  985. static    findspeed (speed)
  986. int    speed;
  987. {
  988.     register struct    speedlist *ps;
  989.  
  990.     for (ps = speeds; ps->value >= 0; ps++)
  991.         if (ps->value == speed)
  992.             return (ps->name);
  993.  
  994.     return (0);
  995. }
  996.  
  997. alarmcatch ()
  998. {
  999.     long    timebuf[2];
  1000.  
  1001.     time (&timebuf[0]);
  1002.     timebuf[1] = timebuf[0];
  1003.  
  1004.     utime (lockfile, timebuf);
  1005.     signal (SIGALRM, alarmcatch);
  1006.     alarm (3600);
  1007. }
  1008.  
  1009. hupcatch ()
  1010. {
  1011.     close (modemfd);
  1012.     unlink (lockfile);
  1013.     signal (SIGHUP, SIG_DFL);
  1014. }
  1015.  
  1016. int    dial (call)
  1017. CALL    *call;
  1018. {
  1019.     char    modemline[64];            /* device name                */
  1020.     char    *modemname;            /* modemcap name of modem        */
  1021.     char    *strcpy (),
  1022.         *strcat ();
  1023. #ifdef    UNIX_S5
  1024.     struct    termio    termio;
  1025. #endif
  1026. #ifdef    UNIX_V7
  1027.     struct    sgttyb    termio;
  1028. #endif
  1029.     int    fd;
  1030.     int    err;
  1031.  
  1032.     strcat (strcpy (modemline, DEVDIR), call->line);
  1033.     strcat (strcpy (lockfile, LOCK), call->line);
  1034.  
  1035.     /*
  1036.      * FIX - Version 7 does not have three operand open(), write
  1037.      * conditional compilation for this here ...
  1038.      */
  1039.  
  1040.     if (access (lockfile, 0) == 0 || (fd = creat (lockfile, 0)) == -1)
  1041.         return (merrno = DV_NT_A);    /* lock existed or couldn't be created    */
  1042.     else
  1043.         close (fd);            /* created lock, now close descriptor    */
  1044.  
  1045.     fd = -1;                /* channel illegal until line is opened    */
  1046.  
  1047.     if ((err = findline (call->line, call->baud)) <= 0)
  1048.         goto error;
  1049.  
  1050.     if ((modemname = findmodem (call->line)) == NULL) { /* can't determine the type of modem    */
  1051.         err = DV_NT_K;
  1052.         goto error;
  1053.     }
  1054.     if ((fd = open (modemline, O_RDWR)) < 0) { /* can't open modem line        */
  1055.         err = L_PROB;
  1056.         goto error;
  1057.     }
  1058. #ifdef    UNIX_S5
  1059.     if (call->attr != (struct termio *) 0) { /* set attributes            */
  1060.         if (ioctl (fd, TCSETA, call->attr) == -1) { /* some ioctl() problem    */
  1061.             err = L_PROB;
  1062.             goto error;
  1063.         }
  1064.     } else {
  1065.         ioctl (fd, TCGETA, &termio);
  1066.         if ((termio.c_cflag = findspeed (call->baud)) == 0) {
  1067.             err = ILL_BD;
  1068.             goto error;
  1069.         }
  1070.         termio.c_cflag |= (CS8|CREAD|HUPCL);
  1071.         termio.c_iflag = 0;
  1072.         termio.c_oflag = 0;
  1073.         termio.c_lflag = 0;
  1074.         termio.c_cc[VMIN] = 1;
  1075.         termio.c_cc[VTIME] = 1;
  1076.         if (ioctl (fd, TCSETA, &termio) == -1) {
  1077.             err = L_PROB;
  1078.             goto error;
  1079.         }
  1080.     }
  1081. #endif
  1082. #ifdef    UNIX_V7
  1083.     if (call->attr != (struct sgttyb *) 0) { /* set attributes            */
  1084.         if (gtty (fd, call->attr) == -1) { /* some gtty() problem */
  1085.             err = L_PROB;
  1086.             goto error;
  1087.         }
  1088.     } else {
  1089.         gtty (fd, &termio);
  1090.         if ((termio.sg_ispeed = findspeed (call->baud)) == 0) {
  1091.             err = ILL_BD;
  1092.             goto error;
  1093.         }
  1094.         termio.sg_ospeed = termio.sg_ispeed;
  1095.         termio.sg_flags = RAW|ANYP;
  1096.         termio.sg_erase = -1;
  1097.         termio.sg_kill = -1;
  1098.         if (stty (fd, &termio) == -1) {
  1099.             err = L_PROB;
  1100.             goto error;
  1101.         }
  1102.     }
  1103. #endif
  1104.     initmodem (modemname, fd);        /* setup modemcap variables        */
  1105.     if (call->telno == (char *) 0)        /* no phone number, connection complete    */
  1106.         goto okay;
  1107.  
  1108.     if (! DI) {                /* modem has no ACU!!!            */
  1109.         err = A_PROB;            /* no ACU to attach to            */
  1110.         goto error;
  1111.     }
  1112.     if (BD != call->baud) {            /* is connection desired at high speed?    */
  1113.         if (BL != call->baud)    {    /* is connection desired at low speed?    */
  1114.             err = ILL_BD;        /* modem can't handle this speed    */
  1115.             goto error;
  1116.         }
  1117.         BD = BL;            /* set baud to low baud rate        */
  1118.         CO = CL;            /* set connect reply to low baud reply    */
  1119.     }
  1120.     if (err = mdial (call->telno, fd))     /* some error trying to dial        */
  1121.         goto error;
  1122.  
  1123.     signal (SIGALRM, alarmcatch);        /* set catcher for ALARM clock        */
  1124.     signal (SIGHUP, hupcatch);        /* set catcher for HANG UP        */
  1125.     alarm (3600);                /* set clock for 1 hour to touch lock    */
  1126.  
  1127. okay:
  1128.     return (modemfd = fd);
  1129.  
  1130. error:
  1131.     unlink (lockfile);
  1132.     if (fd > 2)
  1133.         close (fd);
  1134.     return (merrno = err);
  1135. }
  1136.  
  1137. void    undial (fd)
  1138. int    fd;
  1139. {
  1140.     if (fd > 2)
  1141.         close (fd);
  1142.  
  1143.     unlink (lockfile);
  1144.     alarm (0);
  1145. }
  1146. SHAR_EOF
  1147. fi
  1148. if test -f 'call.c'
  1149. then
  1150.     echo shar: "will not over-write existing file 'call.c'"
  1151. else
  1152. cat << \SHAR_EOF > 'call.c'
  1153. #include <dial.h>
  1154. #include <stdio.h>
  1155.  
  1156. CALL    call;
  1157.  
  1158. main (argc, argv)
  1159. int    argc;
  1160. char    **argv;
  1161. {
  1162.     if (strcmp (argv[0], "call") == 0)
  1163.         exit (do_call (argc, argv));
  1164.     else if (strcmp (argv[0], "hangup") == 0)
  1165.         exit (do_hup (argv, argv));
  1166.  
  1167.     fprintf (stderr, "usage: call tty baud telno\n");
  1168.     fprintf (stderr, "       hangup tty baud\n");
  1169.     exit (1);
  1170. }
  1171.  
  1172. do_call (argc, argv)
  1173. int    argc;
  1174. char    **argv;
  1175. {
  1176.     int    fd;
  1177.  
  1178.     if (argc < 4) {
  1179.         fprintf (stderr, "usage: call tty baud telno\n");
  1180.         exit (1);
  1181.     }
  1182.     call.line = argv[1];
  1183.     call.baud = atoi (argv[2]);
  1184.     call.telno = argv[3];
  1185.     
  1186.     fd = dial (&call);
  1187.     if (fd < 0) {
  1188.         merror (argv[0]);
  1189.         exit (2);
  1190.     }
  1191.     undial (fd);
  1192.     return (0);
  1193. }
  1194.  
  1195. do_hup (argc, argv)
  1196. int    argc;
  1197. char    **argv;
  1198. {
  1199.     int    fd;
  1200.  
  1201.     if (argc < 3) {
  1202.         fprintf (stderr, "usage: hangup tty baud\n");
  1203.         exit (1);
  1204.     }
  1205.     call.line = argv[1];
  1206.     call.baud = atoi (argv[2]);
  1207.     
  1208.     fd = dial (&call);
  1209.     if (fd < 0) {
  1210.         merror (argv[0]);
  1211.         exit (2);
  1212.     }
  1213.     hangup (fd);
  1214.     undial (fd);
  1215.     return (0);
  1216. }
  1217. SHAR_EOF
  1218. fi
  1219. exit 0
  1220. #    End of shell archive
  1221. -- 
  1222. John F. Haugh II        HECI Exploration Co. Inc.
  1223. UUCP:    ...!ihnp4!killer!jfh    11910 Greenville Ave, Suite 600
  1224. "Don't Have an Oil Well?"    Dallas, TX. 75243
  1225. " ... Then Buy One!"        (214) 231-0993
  1226.